package com.whz.generic.serializer;

import com.esotericsoftware.kryo.Kryo;
import com.esotericsoftware.kryo.io.Input;
import com.esotericsoftware.kryo.io.Output;
import lombok.SneakyThrows;

import java.io.ByteArrayOutputStream;
import java.util.Arrays;

/**
 * kryo 序列化方式
 *
 * @author whz
 */
public class KryoRedisSerializer extends AbstractRedisSerializer {
    private static final ThreadLocal<Kryo> KRYO = ThreadLocal.withInitial(Kryo::new);


    @SneakyThrows
    @Override
    public byte[] serialize(Object t) {
        if (t == null) {
            return SerializationUtils.EMPTY_ARRAY;
        }

        Kryo kryo = KRYO.get();
        // 设置成false 序列化速度更快，但是遇到循环应用序列化器会报栈内存溢出
        kryo.setReferences(false);
        kryo.register(t.getClass());

        try (ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
             Output output = new Output(outputStream)) {
            kryo.writeClassAndObject(output, t);
            output.flush();
            return outputStream.toByteArray();
        } finally {
            KRYO.remove();
        }
    }

    @Override
    public Object deserialize(byte[] bytes) {
        return deserialize(bytes, Object.class);
    }

    @SneakyThrows
    @SuppressWarnings("unchecked")
    public <T> T deserialize(byte[] bytes, Class<T> resultType) {
        if (SerializationUtils.isEmpty(bytes)) {
            return null;
        }

        if (Arrays.equals(getNullValueBytes(), bytes)) {
            return null;
        }

        Kryo kryo = KRYO.get();
        // 设置成false 序列化速度更快，但是遇到循环应用序列化器会报栈内存溢出
        kryo.setReferences(false);
        kryo.register(resultType);

        try (Input input = new Input(bytes)) {
            return (T) kryo.readClassAndObject(input);
        } finally {
            KRYO.remove();
        }
    }
}